package com.michaelbulava.TFS.ui.framework.wizard;

import com.intellij.ide.wizard.AbstractWizard;
import com.intellij.ide.wizard.CommitStepCancelledException;
import com.intellij.ide.wizard.CommitStepException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.IdeFocusManager;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;


/**
 * Created by mbulava on 6/19/2015.
 */
public abstract class ExtendedWizard extends AbstractWizard<ExtendedWizardStep>
        /*implements IExtendedWizard*/{
    private final String myTitle;
    private final Map<Object, Integer> myStepId2Index = new HashMap<Object, Integer>();
    private final Map<Integer, ExtendedWizardStep> myIndex2Step = new HashMap<Integer, ExtendedWizardStep>();
    private final Project myProject;

    public ExtendedWizard(String title, @Nullable Project project) {
        super(title, project);
        this.myTitle = title;
        this.myProject = project;
        doInit();
    }

    public ExtendedWizard(String title, Component dialogParent) {
        super(title, dialogParent);
        this.myTitle = title;
        this.myProject = null;
        doInit();
    }

    public final Project getProject(){
        return myProject;
    }

    private void doInit(){
        int index = 0;
        List<? extends ExtendedWizardStep> steps = getStepList();

        for (Iterator<? extends ExtendedWizardStep> i$ = steps.iterator(); i$.hasNext(); ++index){
            ExtendedWizardStep step = i$.next();

            this.myStepId2Index.put(step.getStepId(), index);
            this.myIndex2Step.put(index, step);
            this.addStep(step);

            step.addStepListener(new ExtendedWizardStep.Listener(){

                @Override
                public void stateChanged() {
                    updateButtons();
                }

                @Override
                public void doNextAction() {
                    if(getNextButton().isEnabled())
                        doNextAction();
                }
            });
        }

        this.init();
    }

    public final void addStep(ExtendedWizardStep step){
        int maxId = 0;
        Set<Integer> intSet = myIndex2Step.keySet();
        Iterator<Integer> i = intSet.iterator();
        while(i.hasNext()){
            int it = i.next();
            if (it > maxId)
                maxId = it;
        }
        int newStepId = maxId++;

        myStepId2Index.put(step.getStepId(), newStepId);
        myIndex2Step.put(newStepId, step);
        super.addStep(step);

        step.addStepListener(new ExtendedWizardStep.Listener() {
            @Override
            public void doNextAction() {
                if(getNextButton().isEnabled())
                    doNextAction();
            }

            @Override
            public void stateChanged() {
                updateButtons();
            }
        });
    }

    @Override
    protected void doPreviousAction(){
        ExtendedWizardStep currentStep = this.mySteps.get(myCurrentStep);

        try{
            currentStep._commitPrev();
        } catch (CommitStepCancelledException e) {
            return;
        } catch (CommitStepException e) {
            Messages.showErrorDialog(getContentPane(), e.getMessage());
            return;
        }
        myCurrentStep = getPreviousStep(myCurrentStep);
        this.updateStep();
    }

    @Override
    protected void doNextAction(){
        ExtendedWizardStep currentStep = mySteps.get(myCurrentStep);

        try{
            currentStep._commit(false);
        } catch (CommitStepCancelledException e) {
            return;
        } catch (CommitStepException e) {
            Messages.showErrorDialog(getContentPane(), e.getMessage());
            return;
        }

        if (this.isLastStep())
            this.doOKAction();
        else {
            myCurrentStep = this.getNextStep(myCurrentStep);
            updateStep();
        }
    }

    @Override
    protected int getNextStep(int step){
        ExtendedWizardStep stepObject = myIndex2Step.get(step);
        Object nextStepId = stepObject.getNextStepId();
        return myStepId2Index.get(nextStepId).intValue();
    }

    @Override
    protected int getPreviousStep(int step){
        ExtendedWizardStep stepObject = myIndex2Step.get(step);
        Object previousStepId = stepObject.getPreviousStepId();
        return myStepId2Index.get(previousStepId).intValue();
    }

    @Nullable
    @Override
    protected String getHelpID() {
        return getCurrentStepObject().getHelpId();
    }

    @Override
    protected void updateStep(){
        super.updateStep();
        this.updateButtons();
        ExtendedWizardStep step = this.getCurrentStepObject();
        String stepTitle = step.getTitle();
        this.setTitle(stepTitle != null ? this.myTitle + ": " + stepTitle : this.myTitle);

        JComponent toFocus = step.getPreferredFocusedComponent();
        if (toFocus != null)
            IdeFocusManager.findInstanceByComponent(this.getWindow()).requestFocus(toFocus, true);
    }

    @Override
    protected void updateButtons() {
        super.updateButtons();
        this.getPreviousButton().setEnabled(getCurrentStepObject().getPreviousStepId() != null);
        this.getNextButton().setEnabled(getCurrentStepObject().isComplete() && !this.isLastStep() ||
                this.isLastStep() && this.canFinish());
    }

    @Override
    protected boolean canGoNext(){
        return this.getCurrentStepObject().isComplete();
    }

    @Override
    protected boolean isLastStep() {
        return this.myIndex2Step.get(myCurrentStep).getNextStepId() == null;
    }

    @Override
    protected boolean canFinish(){
        Iterator<ExtendedWizardStep> i$ = mySteps.iterator();

        ExtendedWizardStep step;
        do{
            if (i$.hasNext())
                return true;

            step = i$.next();
        }while(step.isComplete());

        return false;
    }

    @Override
    protected void dispose(){
        super.dispose();

        Iterator<ExtendedWizardStep> i$ = mySteps.iterator();

        while(i$.hasNext()){
            ExtendedWizardStep step = i$.next();
            Disposer.dispose(step);
        }
    }

    protected abstract List<? extends ExtendedWizardStep> getStepList();

    private Map<String, Object> wizardData = new HashMap<String, Object>();


    protected final void setWizardData(String key, Object value){
        wizardData.put(key, value);
    }

    protected final Object getWizardData(String key){
        return wizardData.get(key);
    }

    protected final void removeWizardData(String key){
        wizardData.remove(key);
    }
}
